package hu.uszeged.inf.wlab.stunner.screens.discovery.task;

import hu.uszeged.inf.wlab.stunner.R;
import hu.uszeged.inf.wlab.stunner.database.dtos.MobileNetInfoDTO;
import hu.uszeged.inf.wlab.stunner.database.dtos.WifiInfoDTO;
import hu.uszeged.inf.wlab.stunner.screens.discovery.infobuilders.MobileNetworkInfoBuilder;
import hu.uszeged.inf.wlab.stunner.screens.discovery.infobuilders.MobileNetworkInfoBuilder.NetworkTypes;
import hu.uszeged.inf.wlab.stunner.screens.discovery.infobuilders.Parser;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.view.View;

/**
 * {@link OnClickListener} implementation which also serves as connection test. Checks if there is any active connection, and tries to get
 * as much info as possible via the active connection interface. Also handles error events.
 * 
 * @author szelezsant
 */
public class DeviceConnectionTester implements View.OnClickListener {

	/** The interface implementation to listen for the declared events. */
	private final TestEventsListener listener;
	/** The {@link Context} instance to gain access to resources. */
	private final Context context;

	/**
	 * Constructor. Throws {@link IllegalArgumentException} if any of the arguments is null.
	 * 
	 * @param context - the calling context. Mandatory.
	 * @param listener - the listener to get notified about the discovery events. Mandatory.
	 */
	public DeviceConnectionTester(final Context context, final TestEventsListener listener) {
		if (null == context || null == listener) {
			throw new IllegalArgumentException("both arguments must be initialized.");
		}
		this.context = context;
		this.listener = listener;
	}

	@Override
	public void onClick(final View button) {
		listener.onTestStart();

		final ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
		final NetworkInfo networkInfo = connManager.getActiveNetworkInfo();

		/* if there is no active connection, we prompt the user to enable an adapter */
		if (null == networkInfo) {
			final DialogInterface.OnClickListener dialogListener = new DialogInterface.OnClickListener() {

				@Override
				public void onClick(final DialogInterface dialog, final int which) {
					/* if he declines the offer, finish the activity */
					if (DialogInterface.BUTTON_NEGATIVE == which) {
						listener.onConnectionError(true);
						/* else navigate to the wifi settings */
					} else if (DialogInterface.BUTTON_POSITIVE == which) {
						dialog.dismiss();
						listener.onConnectionError(false);
						context.startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
					}
				}
			};
			new AlertDialog.Builder(context).setMessage(R.string.no_connection).setTitle(R.string.error)
					.setNegativeButton(android.R.string.cancel, dialogListener).setPositiveButton(R.string.settings, dialogListener)
					.create().show();
			/* else if the connection is active, check the type and start the discovery */
		} else if (networkInfo.isConnected()) {
			String localIp = null;
			// get mobile network related data
			final int netType = networkInfo.getType();
			final MobileNetInfoDTO mobileNetInfoDTO = new MobileNetInfoDTO();
			if (netType == ConnectivityManager.TYPE_MOBILE) {
				localIp = MobileNetworkInfoBuilder.getIPFormatted(context);
			}
			final TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
			mobileNetInfoDTO.setNetworkType(NetworkTypes.getByBalue(telephonyManager.getNetworkType()).name());
			mobileNetInfoDTO.setCarrier(telephonyManager.getNetworkOperatorName());

			// get the connection data available on the device
			final WifiInfoDTO wifiInfoDTO = new WifiInfoDTO();
			final WifiInfo wifiInfo = ((WifiManager) context.getSystemService(Context.WIFI_SERVICE)).getConnectionInfo();
			wifiInfoDTO.setMacAddress(wifiInfo.getMacAddress());
			if (netType == ConnectivityManager.TYPE_WIFI || netType == ConnectivityManager.TYPE_WIMAX) {
				localIp = Parser.parseIp(wifiInfo.getIpAddress());
				wifiInfoDTO.setBandwidth(wifiInfo.getLinkSpeed() + " " + WifiInfo.LINK_SPEED_UNITS);
				wifiInfoDTO.setRssi(wifiInfo.getRssi());
				wifiInfoDTO.setSsid(wifiInfo.getSSID());
			}
			listener.onTestComplete(localIp, mobileNetInfoDTO, wifiInfoDTO);
		} else {
			listener.onConnectionNotReady();
		}
	}

	/**
	 * Interface to allow the listener to react the discovery events.
	 * 
	 * @author szelezsant
	 */
	public interface TestEventsListener {
		/**
		 * Invoked when the discovery has started.
		 */
		public void onTestStart();

		/**
		 * Invoked when the connection could not established, because there was no active network interface.
		 * 
		 * @param userDeclined - indicates if the user has declined the option to enable an interface
		 */
		public void onConnectionError(boolean userDeclined);

		/**
		 * Invoked when the connection is not yet established.
		 */
		public void onConnectionNotReady();

		/**
		 * Invoked when the discovery was successfully completed.
		 * 
		 * @param localIp local ip
		 * @param mobileNetInfoDTO - mobile network related info
		 * @param wifiInfoDTO - WIFI connection related info
		 */
		public void onTestComplete(String localIp, final MobileNetInfoDTO mobileNetInfoDTO, final WifiInfoDTO wifiInfoDTO);
	}
}
